import * as fs from "fs";
import * as path from "path";
import * as vscode from 'vscode';
import { executor } from "./executor";
import UiPanel from "./views/uiPanel";
import { $r, getLanguage } from "./utils";
import { globalData } from "./globalData";

export class cangjie {
    public static async createProject() {
        try {
            const projectName = await vscode.window.showInputBox({
                prompt: $r('enterPjName'),
                placeHolder: $r('enterPjPlaceHolder')
            });
            const projectPath = await vscode.window.withProgress<string>(
                { location: vscode.ProgressLocation.Notification, cancellable: false },
                async (progress) => {
                    progress.report({ message: $r('createPjTips', projectName) });
                    try {
                        if (!projectName) {
                            return '';
                        }
                        const folders = await vscode.window.showOpenDialog({
                            openLabel: $r('select'),
                            canSelectFolders: true,
                            canSelectFiles: false,
                        }), folder = folders ? folders[0].fsPath : undefined;
                        if (!folder) {
                            return '';
                        }
                        const projectPath = path.join(folder, projectName),
                            uri = vscode.Uri.parse(projectPath);
                        await vscode.workspace.fs.createDirectory(uri);
                        return this.initCjpm(projectPath);
                    } catch (error) {
                        return "";
                    }
                }
            );
            if (projectPath.trim() === "") {
                vscode.window.showErrorMessage($r('createPjFailed'));
                return;
            }
            const result = await vscode.window.showInformationMessage(
                $r('createPjDone'),
                $r('open'),
                $r('cancel')
            );
            if (result === $r('open')) {
                vscode.commands.executeCommand("vscode.openFolder", vscode.Uri.file(projectPath), false);
            }
        } catch (err) {
            vscode.window.showErrorMessage(`${err}`);
        }
    }

    public static async initProject(fileUri: vscode.Uri) {
        if (fileUri && fileUri.fsPath) {
            const targetPath = path.extname(fileUri.path).length > 0 ? path.dirname(fileUri.path) : fileUri.path;
            vscode.commands.executeCommand("vscode.openFolder", vscode.Uri.file(targetPath), false);
            await this.initCjpm(targetPath);
        }
    }

    public static async dependenciesTools(extensionPath: string, fileUri: vscode.Uri) {
        if (fileUri && fileUri.fsPath) {
            UiPanel.createOrShow(extensionPath, fileUri);
        }
    }

    public static updateDependencies(fileUri: vscode.Uri) {
        if (fileUri && fileUri.fsPath) {
            const targetPath = path.extname(fileUri.path).length > 0 ? path.dirname(fileUri.path) : fileUri.path;
            executor.runInTerminal(`cd ${targetPath}`);
            executor.runInTerminal(`cjpm update`);
        }
    }

    public static buildProject() {
        executor.runInTerminal(`cjpm build`);
    }

    public static cleanProject(fileUri: vscode.Uri) {
        if (fileUri && fileUri.fsPath) {
            const targetPath = path.extname(fileUri.path).length > 0 ? path.dirname(fileUri.path) : fileUri.path;
            executor.runInTerminal(`cd ${targetPath}`);
            executor.runInTerminal(`cjpm clean`);
        }
    }

    public static async createFile(fileUri: vscode.Uri) {
        const fileName = await vscode.window.showInputBox({
            prompt: $r('enterFileName'),
            placeHolder: $r('enterFilePlaceHolder')
        });
        if (fileName && fileUri && fileUri.fsPath) {
            const targetPath = path.extname(fileUri.path).length > 0 ? path.dirname(fileUri.path) : fileUri.path,
                uri = vscode.Uri.parse(path.join(targetPath, `${fileName}.cj`));
            await vscode.workspace.fs.writeFile(uri, new Uint8Array());
        }
    }

    public static async buildFile(fileUri: vscode.Uri) {
        if (fileUri && fileUri.fsPath) {
            executor.runInTerminal(`cjc "${fileUri.path}"`);
        }
    }

    static initCjpm(projectPath: string): Promise<string> {
        return new Promise(async (resolve, reject) => {
            try {
                let sdkPath = globalData.sdkPath;
                const file = (process.platform === 'linux' || process.platform === 'darwin') ? path.join(sdkPath, 'envsetup.sh') : path.join(sdkPath, 'envsetup.bat');
                if (!sdkPath) {
                    const count = 0,
                        config = vscode.workspace.getConfiguration("cangjieTools");
                    sdkPath = await this.setSdkPath(config, count);
                    if (sdkPath?.toString().trim() !== '') {
                        const initCmd = (process.platform === 'linux' || process.platform === 'darwin') ? `source "${file}"` : `${file}`;
                        executor.runInTerminal(initCmd);
                        executor.runInTerminal(`cd "${projectPath}"`);
                        executor.runInTerminal('cjpm init');
                        resolve(projectPath);
                    }
                } else {
                    const initCmd = (process.platform === 'linux' || process.platform === 'darwin') ? `source "${file}"` : `${file}`;
                    executor.runInTerminal(initCmd);
                    executor.runInTerminal(`cd "${projectPath}"`);
                    executor.runInTerminal('cjpm init');
                    resolve(projectPath);
                }
                this.getSdkVer(sdkPath);
            } catch (e) {
                vscode.window.showErrorMessage(`${e}`);
            }
            reject($r('initPjFailed'));
        });
    }

    static async setSdkPath(config: vscode.WorkspaceConfiguration, count: number): Promise<string> {
        let result = '';
        const sdkPath = await vscode.window.showOpenDialog({
            openLabel: $r('select'),
            canSelectFolders: true,
            canSelectFiles: false
        });
        try {
            const file = (process.platform === 'linux' || process.platform === 'darwin') ? path.join(sdkPath?.[0]?.path ?? '', 'envsetup.sh') : path.join(sdkPath?.[0]?.path ?? '', 'envsetup.bat');
            fs.accessSync(file);
            await config.update('sdkPath', sdkPath, vscode.ConfigurationTarget.Global);
            result = sdkPath?.[0].path ?? '';
        } catch (e) {
            if (count > 2) {
                vscode.window.showErrorMessage($r('retrySdkFailed'));
            } else {
                count++;
                vscode.window.showErrorMessage($r('setSkdFailed'));
                result = await this.setSdkPath(config, count);
            }
        }
        return result;
    }

    static async getSdkVer(sdkPath: string) {
        const result = await executor.exec(`${path.join(sdkPath, 'bin', 'cjc')} -v`);
        const regex = /(\d+\.\d+\.\d+)/;
        const match = regex.exec(result);
        globalData.sdkVersion = match?.[0].toString() ?? '';
        if (globalData.sdkVersion) {
            vscode.window.showInformationMessage($r('showSdkVer', globalData.sdkVersion));
        }
    }

    static showAbout(extensionPath: string) {
        const panel = vscode.window.createWebviewPanel('cj.about', $r('aboutTitle'), vscode.ViewColumn.One, {
            enableScripts: true,
            localResourceRoots: [vscode.Uri.file(path.join(extensionPath, "app"))],
            retainContextWhenHidden: true,
        });
        const lng = getLanguage(),
            appDistPath = path.join(extensionPath, 'res', 'views', lng),
            appDistPathUri = vscode.Uri.file(appDistPath),
            indexPath = path.join(appDistPath, 'about.html');
        const baseUri = panel.webview.asWebviewUri(appDistPathUri);
        panel.webview.html = fs.readFileSync(indexPath, { encoding: 'utf8' }).replace('<base href="/">', `<base href="${String(baseUri)}/">`);
        panel.onDidDispose(() => panel.dispose(), null);
    }
}